package person.bangbang.im.Androidgin;

import person.bangbang.im.Androidgin.Framework.Account;
import person.bangbang.im.Androidgin.Framework.Accounts;
import person.bangbang.im.Androidgin.Framework.Conversation;
import person.bangbang.im.Androidgin.Framework.Conversations;
import person.bangbang.im.Androidgin.Framework.Message;
import person.bangbang.im.Androidgin.Framework.ProtocolSpec;
import person.bangbang.im.Androidgin.Framework.Sound;
import person.bangbang.im.Androidgin.Framework.StatusType;
import person.bangbang.im.Androidgin.Framework.Conversation.OnImEvent;
import person.bangbang.im.Androidgin.Framework.Conversations.OnConversationsEvent;
import person.bangbang.im.Androidgin.Util.Log;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

/** 
 * the main logic.
 * 
 * @author bangbang.song@gmail
 *
 */
public class AndroidginService extends Service {
	private final static String TAG = "Androidgin.AndroidginService";
	private final static boolean L_DEBUG = true;
	
	// TODO move this to Account
	public final static int STATE_NULL = -1;
	public final static int STATE_SIGNNED = 0;
	public final static int STATE_SIGNNING = 1;
	public final static int STATE_SIGNOFF = 2;
	
	private int mState = STATE_NULL;
	private Context mCon;

	private  String mFormatNotifyString;

	private LocalBinder mBinder = new LocalBinder();
	private AndroidginService mSelf;
	
	private Accounts mAcc = Accounts.getInstance();
	private Conversations mChats = Conversations.getInstance();
	private Sound mSound;
	private AndroidginPref mPref;
	
	private Notify mNotify;
	
	/**
	 * current chat i am talking to.
	 */
	@SuppressWarnings("unused")
	private Conversation mCurrentChat = null;
	
	private OnConversationsEvent mChatEvent = new MyChatEvent();
	
	public void setCurrentChat(Conversation c) {
		mCurrentChat = c;
	}
	/**
	 * @deprecated directly use the Accounts to do.
	 * 
	 * @param protocolId
	 * @param userName
	 * @param loginType
	 * @return null if the wanted account has been created, u MUST check this situation.
	 */
	public Account createAccount(String protocolId, String userName, String passward, StatusType loginType) {
		return mAcc.createAccount(protocolId, userName, passward, loginType);

	}
	/**
	 * TODO: dynamic this function.
	 * 
	 * currently, we just hard-coding here, a better 
	 * solution is needed.
	 * 
	 * ::IMPL::
	 * 
	 * @return supported protocol id String.
	 * 
	 * @deprecated
	 */
	public String[] getSuppoetedProtocolIdStr() { 
		return new String[] {"loopback",
							 "fetion",// FETION step 1
				             "ooxx"
				             };
	}
	@Deprecated
	public StatusType[] getStatusTypebyIdStr(String id) {
		StatusType[] array = new StatusType[]{};
		int i = 0;
		
		// must be matched with the protocol relatively.
		if ("loopback" == id) {
			//ArrayIndexOutOfBoundsException
//			array[i++] = new StatusType(10, "online");
//			array[i++] = new StatusType(20, "offline");
			array = new StatusType[]{new StatusType(10, "online"),
					                 new StatusType(20, "offline")
			};
		} else if ("ooxx" == id) { // RuntimeException
			array = new StatusType[]{new StatusType(100, "oonline"),
					                 new StatusType(200, "ooffline")
			};
		} else if ("fetion" == id) { // FETION step 2
			array = new StatusType[]{new StatusType(10, "online"),
									 new StatusType(15, "hidemyself"),
					                 new StatusType(20, "offline")
			};
		}
		
		return array;
	}
	public ProtocolSpec[] getSupportProtocl(){
		return new ProtocolSpec[]{
					              new ProtocolSpec(ProtocolSpec.ICON_ID_DEFAULT, //R.drawable.protocol_loopback, 
					            		           "loopback",
					            		           new StatusType[]{new StatusType(StatusType.ONLINE, "online"),
					            		  						    new StatusType(StatusType.OFFLINE, "offline", StatusType.RES_OFFLINE)
					            		  
					              }),
					              new ProtocolSpec(ProtocolSpec.ICON_ID_DEFAULT, //R.drawable.protocol_loopback, 
			            		           "ooxx",
			            		           new StatusType[]{new StatusType(StatusType.ONLINE, "oonline"),
			            		  						    new StatusType(StatusType.OFFLINE, "ooffline", StatusType.RES_OFFLINE)
			            		  
					              }),					              
					              new ProtocolSpec(R.drawable.protocol_fetion, 
					            		           "fetion",
					            		           new StatusType[]{new StatusType(StatusType.ONLINE, "online"),
					  									            new StatusType(StatusType.INVISABLE, "invisable", StatusType.RES_INVISABLE),
					  					                            new StatusType(StatusType.OFFLINE, "offline", StatusType.OFFLINE)
					              									})
								 };
	}
	// you must set this state explicitly. 
	// ohh, is better if auto set?
	public void setState(int state) {
		mState = state;
	}
	public int getState() {
		return mState;
	}
    @Override
    public void onCreate() {
    	// TODO Auto-generated method stub
    	super.onCreate();
    	init();
    }
    @Override
    public void onDestroy() {
    	// TODO Auto-generated method stub
    	super.onDestroy();
    	mChats.unRegOnConversationsListener(mChatEvent);
    }
    
    private void init() {
    	mCon = getApplicationContext();
    	mSelf = this;
    	mSound = Sound.getInstance(mCon);
    	mPref = AndroidginPref.getInstance(mCon);
    	mNotify = Notify.getInstance(mCon);
		mFormatNotifyString = mCon.getResources().getString(R.string.notify_title_format);

    	mChats.regOnConversationsListener(mChatEvent);
    }
    
    /* 
     * if the chat to which the msg belongs is active, do nothing.
     * if NOT show a notification in bar.
     */
    private void doNotifyRcvdMsg(Message msg) {
    	if (!mPref.isSlient() && mPref.notifyRcvdMsg()) {
    		mSound.playEvent(Sound.ID_BUDDY_ARRIVE);
    	}
    	Conversation c = mChats.findConversation(msg.getFrom());
    	
    	if (L_DEBUG) Log.d(TAG, "chat the rcvd msg belongs :" + c + 
    			                "\n" + "current chat:" + mCurrentChat);
    	if (c != (mCurrentChat)) { // notify it
    		// TODO set to protocol's res accordingly.
    		mNotify.notifyMsg(msg, c.getNotifyId());
    	} else {
    		; // ignore
    	}
    }

    @Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return mBinder;
	}
	
	public class LocalBinder extends Binder {
		public AndroidginService getService(){
			return mSelf;
		}
	}
	
	private class MyChatEvent implements OnConversationsEvent {
		public void onDelete(Conversation c) {}
		public void onNew(Conversation c) {
			c.regOnImListener(new OnImEvent() {
				public void onErrIm(int code, String detail) {}
				public void onRcvdIm(Message msg) {
					doNotifyRcvdMsg(msg);
				}
				public void onSentIm(Message msg) {}
			});
		}
}
}
